<script setup>
import { ref, computed, onMounted, onBeforeUnmount } from 'vue';
import FileIcon from './FileIcon.vue';
import { theme as themeStore, subscribe as subscribeTheme } from '../assets/theme.js';

const props = defineProps({
  node: { type: Object, required: true },
  depth: { type: Number, default: 0 },
  isExpanded: { type: Function, required: true },
  toggle: { type: Function, required: true },
  select: { type: Function, required: true },
  loadChildrenIfNeeded: { type: Function, required: true },
  getIcon: { type: Function, default: null },
  indent: { type: Number, default: 12 },
  selectedId: { type: [String, Number], default: null },
  getChildren: { type: Function, required: true },
});

const isDir = computed(() => props.node.isDir === true || props.node.is_dir === true || props.node.isFolder === true);
const isLeaf = computed(() => props.node.isLeaf === true || (!isDir.value));
const expanded = computed(() => props.isExpanded(props.node.id));

function onToggle(e) {
  e?.stopPropagation?.();
  props.toggle(props.node);
}
function onSelect(e) {
  props.select(props.node, e);
}

const paddingLeft = computed(() => (props.depth * props.indent) + 'px');
const fileIconTheme = ref(themeStore.fileIconTheme);
let unsubscribe = null;
onMounted(() => { unsubscribe = subscribeTheme((t) => { fileIconTheme.value = t.fileIconTheme; }); });
onBeforeUnmount(() => { if (unsubscribe) try { unsubscribe(); } catch {} });

function minimalIconFor(name) {
  const n = String(name || '').toLowerCase();
  if (n.endsWith('.js') || n.endsWith('.jsx')) return '🟨';
  if (n.endsWith('.ts') || n.endsWith('.tsx')) return '🟦';
  if (n.endsWith('.vue')) return '🟩';
  if (n.endsWith('.json')) return '🟫';
  if (n.endsWith('.md') || n.endsWith('.markdown')) return '📘';
  if (n.endsWith('.css') || n.endsWith('.scss') || n.endsWith('.sass')) return '🎨';
  if (n.endsWith('.rs') || n.endsWith('.toml')) return '🦀';
  if (n.match(/\.(png|jpe?g|gif|svg|webp)$/)) return '🖼️';
  return '📄';
}

const icon = computed(() => {
  if (isDir.value) return '';
  if (props.getIcon) return props.getIcon(props.node, { isDir: isDir.value, expanded: expanded.value }) || '';
  if (fileIconTheme.value === 'none') return '';
  if (fileIconTheme.value === 'minimal') return minimalIconFor(props.node.label);
  // 'vscode' (default): handled in template via <FileIcon/>
  return 'vscode';
});

const isRootDir = computed(() => props.depth === 0 && isDir.value);

</script>

<template>
  <div class="select-none min-w-0">
    <div
      class="flex items-center gap-1 rounded px-2 py-0.5 hover:bg-slate-200/40 dark:hover:bg-white/10 cursor-pointer min-w-0 transition-colors duration-150"
      :class="selectedId===node.id ? 'bg-accent/15 dark:bg-accent/25' : ''"
      :style="{ paddingLeft }"
      @click.stop="onSelect"
      @contextmenu.prevent.stop="(e)=> props.select(props.node, e, { context: true })"
      data-tree-row="1"
      :data-depth="depth"
      :data-isdir="isDir ? '1' : '0'"
      :data-id="String(node.id)"
      :data-label="String(node.label || '')"
    >
      <template v-if="isDir">
        <button
          class="inline-flex h-4 w-4 items-center justify-center text-slate-500 dark:text-neutral-500"
          :aria-label="expanded ? 'Collapse' : 'Expand'"
          :aria-expanded="expanded"
          @click.stop="onToggle"
        >
          <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"
               :class="['h-3 w-3 transition-transform transform', expanded ? 'rotate-90' : 'rotate-0']">
            <path d="M9 6l6 6-6 6" />
          </svg>
        </button>
      </template>
      <span v-else class="inline-flex h-4 w-4"></span>
      <span v-if="icon" class="inline-flex items-center justify-center ml-1 mr-1">
        <template v-if="icon==='vscode'">
          <FileIcon :name="node.label" :size="16" />
        </template>
        <template v-else>
          {{ icon }}
        </template>
      </span>
      <span class="truncate" :class="isRootDir ? 'font-semibold uppercase text-slate-500 dark:text-neutral-400' : ''">{{ node.label }}</span>
    </div>
    <div v-if="isDir && expanded" class="min-w-0">
      <TreeNode
        v-for="child in getChildren(node)"
        :key="child.id"
        :node="child"
        :depth="depth + 1"
        :isExpanded="isExpanded"
        :toggle="toggle"
        :select="select"
        :loadChildrenIfNeeded="loadChildrenIfNeeded"
        :getIcon="getIcon"
        :indent="indent"
        :selectedId="selectedId"
        :getChildren="getChildren"
        :stickyIndexMap="stickyIndexMap"
        :rowHeight="rowHeight"
      />
    </div>
  </div>
</template>

<script>
export default { name: 'TreeNode' };
</script>


